require 'depac-common/softlayer'
require 'depac-deployment/environment_configuration'
require 'depac-deployment/helper'
require 'depac-deployment/configure'
require 'depac-deployment/provision'
require 'depac-deployment/update_database'
require 'depac-deployment/add_instance'
require 'depac-deployment/remove_instance'
require 'depac-deployment/newrelic_configuration'
require 'depac-deployment/update_ihsplugin'
require 'depac-common/constants'
require 'depac-common/utils'
require 'pp'
require 'net/http'

#Start point for updateEnv
def updateEnvironment(existingEnvConfigObject, removedObjects, updateconfigpath, buildLabel, outputFilePath)
	updSequence = nil
	delay=120
	if(updateconfigpath==nil)
		updSequence=[
        {'role' => "database"},
        {'role' => "appserver"},       
       	{'role' => "agent"},
       	{'role' => "intg"}       	
     	 ]
	else
		if(updateconfigpath.kind_of?(String)) 
  			if (File.exists?(updateconfigpath))
  				updateconfig = YAML.load_file(updateconfigpath)
  				updSequence = updateconfig["sequence"]
  				delay = updateconfig["delay"]
  			else
  				raise "ERROR: File '#{updateconfigpath}' does not exist."
  			end	  	
	  	end
	end
	return startUpdateProcess(existingEnvConfigObject, removedObjects, updSequence, delay, buildLabel, outputFilePath)
	
end

def updateProxyForNRAgent(node, envConfig, enable)
  private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
  ip = node['IP']

  newrelicProxy = ""  
  if envConfig['newrelicConfig'] != nil && envConfig['newrelicConfig']['newrelix_proxyhost'] != nil
    newrelicProxy = envConfig['newrelicConfig']['newrelix_proxyhost']
  end
  if newrelicProxy.empty?
    return
  end

  cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -o StrictHostKeyChecking=no 'iptables -L -n | grep #{newrelicProxy}'"
  output =  `#{cmdstr}`
  if $? == 0
    cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -o StrictHostKeyChecking=no 'iptables -#{enable ? 'I' : 'D' } INPUT -s #{newrelicProxy} -j DROP'"
    Depac::Log.write("INFO", "Executing command: " + cmdstr)
    output =  `#{cmdstr}`

    Depac::Log.write("INFO", output)
    Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)   
  end
end  

def startUpdateProcess(existingEnvConfigObject, removedObjects, updSequence, delay, buildLabel, outputFilePath)
	updatedEnvConfigObj = existingEnvConfigObject
	#removedConfigObj = existingEnvConfigObject.clone
	updSequence.each do |item|		
		case item[Depac::CloudDeploymentConstants::ROLE]
		when Depac::CloudDeploymentConstants::ROLE_DATABASE
			callupdateDb(existingEnvConfigObject,buildLabel,delay, outputFilePath)
		when Depac::CloudDeploymentConstants::ROLE_APPSERVER
			updateApp(existingEnvConfigObject,buildLabel,delay)
		when Depac::CloudDeploymentConstants::ROLE_AGENT
			updateAgent(existingEnvConfigObject,buildLabel,delay)
		when Depac::CloudDeploymentConstants::ROLE_INTG
			updateIntg(existingEnvConfigObject,buildLabel,delay)
		else
			Depac::Log.write("INFO", "Invalid role or role doesn't support updates, ignoring the role - #{item[Depac::CloudDeploymentConstants::ROLE]}")
		end  	
	end	
		
	updateBuildLable(existingEnvConfigObject,buildLabel)
	
	#if no error report during validation window, remove all old instance
       if(!existingEnvConfigObject.getEnvironmentConfiguration()["ifEnableDocker"])
		removeInstance_upateEnv(existingEnvConfigObject, removedObjects, updSequence)
	end
	return existingEnvConfigObject
end
#docker poc
def callupdateDb(existingEnvConfigObject,buildLabel,delay,outputFilePath)
	startTime=Time.now
	Depac::Log.write("INFO", "DB update started at #{startTime}")	
       if(existingEnvConfigObject.getEnvironmentConfiguration()["ifEnableDocker"])
		updatedEnvConfigObj = updateDatabaseForDocker(existingEnvConfigObject, buildLabel, true, startTime.strftime("%Y%m%d%H%M%S"))
       else
         	updatedEnvConfigObj = updateDatabase(existingEnvConfigObject, buildLabel, true, startTime.strftime("%Y%m%d%H%M%S"))
       end
	if(validateDB(updatedEnvConfigObj))
		#writing the db build level to the config file
		config = updatedEnvConfigObj.getEnvironmentConfiguration()
		config["db_build_label"]= buildLabel
		updateOutputYAML(config, outputFilePath)	
	else
		#do rollback here. 
	end
	Depac::Log.write("INFO", "Sleeping for #{delay} seconds after updating DB")
	sleep delay
	return updatedEnvConfigObj
end

#Validate the database after update
def validateDB(updatedEnvConfigObj)
	#TODO: DB update Validation code goes here.
	return true	 
end
def updateApp(existingEnvConfigObject,buildLabel,delay)
	if(existingEnvConfigObject.getEnvironmentConfiguration()["ifEnableDocker"])
		updateInternalForDocker(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_APPSERVER)
	else
		updateInternal(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_APPSERVER)
	end
end
def updateAgent(existingEnvConfigObject,buildLabel,delay)
	if(existingEnvConfigObject.getEnvironmentConfiguration()["ifEnableDocker"])
		updateInternalForDocker(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_AGENT)
  else
		updateInternal(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_AGENT)
  end
end
def updateIntg(existingEnvConfigObject,buildLabel,delay)
  if(existingEnvConfigObject.getEnvironmentConfiguration()["ifEnableDocker"])
    updateInternalForDocker(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_INTG)
  else
    updateInternal(existingEnvConfigObject,buildLabel,delay,Depac::CloudDeploymentConstants::ROLE_INTG)
  end
end
def updateInternal(existingEnvConfigObject,buildLabel,delay,role)

   if existingEnvConfigObject.getNodeConfigurationByRoleAndType(role,Depac::CloudDeploymentConstants::RUNTIME_NODES) !=nil
    #This is for testing
    #testNodeInfoMaps=YAML.load_file("/root/Deployment/deployment_data/test.yml")

	startTime=Time.now
	Depac::Log.write("INFO", "#{role} update started at #{startTime}")
	oldBuildLabel = existingEnvConfigObject.getBuildLabel()
	#read the details of existing app nodes	
	config = existingEnvConfigObject.getNodeConfigurationByRoleAndType(role,Depac::CloudDeploymentConstants::RUNTIME_NODES)
	count = config[Depac::CloudDeploymentConstants::NO_OF_NODES]
	nodeInfo = config[Depac::CloudDeploymentConstants::NODE_INFO]
	oldhostnames = []
	newnodes = []
	nodeInfo.each do |info|
		oldhostnames << info["hostname"]
	end
	if(count == nil)
		count = nodeInfo.length
	end
	for i in 1..count
        addConfigObject=nil
		if(role == Depac::CloudDeploymentConstants::ROLE_APPSERVER)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
				"vmconfig"   => config["vmconfig"],
	   		 	"no_of_nodes"=> 1
	   		 	}]
	   		}	
		elsif(role == Depac::CloudDeploymentConstants::ROLE_AGENT)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
				"vmconfig"   => config["vmconfig"],
	   		 	Depac::CloudDeploymentConstants::AGENT_NODES=> [{"server_name"=>nodeInfo[i-1]["info"]}]
	   		 	}]
	   		}
	   	elsif(role == Depac::CloudDeploymentConstants::ROLE_INTG)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
				"vmconfig"   => config["vmconfig"],
	   		 	Depac::CloudDeploymentConstants::INTG_NODES=> [{"server_name"=>nodeInfo[i-1]["info"]}]
	   		 	}]
	   		}
		end		
   		removeConfigObject = {
		Depac::CloudDeploymentConstants::RUNTIME_NODES=>
			[{
			"role"       => role,			
   		 	"no_of_nodes"=> 1,
   		 	"node_info"  => [{
   		 			"hostname"=>oldhostnames[i-1],
   		 			"IP"=>nodeInfo[i-1]["IP"]
   		 		}]
   		 	}]
   		}
   		
   		if config['vmspecconfig'] !=nil   		
   		
   		   addConfigObject[Depac::CloudDeploymentConstants::RUNTIME_NODES][0]['vmspecconfig']=config['vmspecconfig']
   		   Depac::Log.write("INFO", "vmspecconfig for role #{role} is : #{config['vmspecconfig']}")
   	    end
   		
   		temp = existingEnvConfigObject.clone
		temp.setEnvironmentConfiguration(addConfigObject)

		nodeInfoMap = provisionInstance(temp, buildLabel, existingEnvConfigObject.getEnvironmentName(), i, existingEnvConfigObject)
        
        #for testing
        #nodeInfoMap = testNodeInfoMaps[i-1]
        #Depac::Log.write("INFO", "using test nodeInfomap is: #{nodeInfoMap}")


		nodeInfoParamMap = buildNodeInfoParamMap(existingEnvConfigObject)
		#nodeInfoParamMap contains the details of nodes whose ips are passed as arguments to migration scripts on each new node by configureInstance
		#Ing/Agent servers require their own ip/servernames to be passed so that services can be started.
		if(role == Depac::CloudDeploymentConstants::ROLE_AGENT or role == Depac::CloudDeploymentConstants::ROLE_INTG)
			nodeInfoParamMap[Depac::CloudDeploymentConstants::RUNTIME_NODES][role]=nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES][role]		
		end	
		
        Depac::Log.write("INFO", "nodeInfoParamMap is : #{nodeInfoParamMap }")
		
		# construct original db hostname - 
		# fix for POOL_CONFIG in PLT_DB_POOL table containing old hostname for pool initialization
		oldDBInfo = dbOldHostnameGen(existingEnvConfigObject)
		envconfig = existingEnvConfigObject.getEnvironmentConfiguration()
		envconfig["oldDBInfo"]=oldDBInfo
		# configure instance
		configureInstance(nodeInfoMap, nodeInfoParamMap, envconfig)
		
		# configure newrelic application name 
		configureNRAppName(nodeInfoMap, existingEnvConfigObject.getEnvironmentConfiguration(), "update")
		
		#upldate IHS plugin
		if role == Depac::CloudDeploymentConstants::ROLE_APPSERVER
		  # update IHS plugin configure
	      updateIHSPlugin_internal(nodeInfoMap, Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH, existingEnvConfigObject.getEnvironmentConfiguration(), "add")
		end
		
		newnodes.push(nodeInfoMap)
		#addInstance(addConfigObject,buildLabel)
		if (validateNode(nodeInfoMap,buildLabel,existingEnvConfigObject.getEnvironmentConfiguration()))		    
			Depac::Log.write("INFO", "Sleeping for #{delay} seconds after creating  #{role} instance from new build.")
			sleep delay
			Depac::Log.write("INFO", "soft-removing old #{role} instance")
			#temp.setEnvironmentConfiguration(removeConfigObject)
			#removeInstance(existingEnvConfigObject,temp,"soft")
			
			#if new app node passed validation, we can remove the old app node from IHS (Note: just remove from IHS, instead of remove VM)
            nodeInfoMap=appNodeToNodeInfoMap(removeConfigObject, Depac::CloudDeploymentConstants::RUNTIME_NODES)    
		    if nodeInfoMap !=nil 
		      updateIHSPlugin_internal(nodeInfoMap, Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH, existingEnvConfigObject.getEnvironmentConfiguration(), "remove")
			end
						
		else
		    Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)
		    Depac::Log.write("INFO", "validate process detected error, roll back to previous environment")
            Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)
		    #if any new node validation fail, refash IHS plugin with existing server then exit
            nodeInfoMap=appNodeToNodeInfoMap(existingEnvConfigObject.getEnvironmentConfiguration(), Depac::CloudDeploymentConstants::RUNTIME_NODES)    
		    if nodeInfoMap !=nil 
		      updateIHSPlugin_internal(nodeInfoMap, Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH, existingEnvConfigObject.getEnvironmentConfiguration(), "replace")
			end
			 
			exit 3
		end 		
	end
	updateEnvConfigObject(newnodes,role,existingEnvConfigObject,buildLabel)
	return existingEnvConfigObject	
  end
end

#docker poc
#The db hostname in property files is of format buildLabel-database.ibm.com and this method constructs that hostname. 
def dbOldHostnameGen(existingEnvConfigObject)	
	config = existingEnvConfigObject.getNodeConfigurationByRoleAndType(Depac::CloudDeploymentConstants::ROLE_DATABASE,Depac::CloudDeploymentConstants::RUNTIME_NODES)
	nodeInfo = config[Depac::CloudDeploymentConstants::NODE_INFO]
	hostname = nodeInfo[0]["hostname"]	
	envName = existingEnvConfigObject.getEnvironmentName()
	return {
				"hostname" => hostname.split(envName.downcase)[0].upcase+"database.ibm.com",
				"IP"=>nodeInfo[0]["IP"]
			}
end
def validateNode(nodeInfoMap,buildLabel,config)
	nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES].each do |role, nodeInfoArr|
		nodeInfoArr.each do |hostnameIPMap|
			hostname = hostnameIPMap['hostname']
			ip = hostnameIPMap['IP']
			Depac::Log.write("INFO", "Validating Instance with ip #{ip} for role #{role} ")
			retry_count = 3
			
			if(role==Depac::CloudDeploymentConstants::ROLE_APPSERVER)
				Depac::Log.write("INFO", "Waiting for appserver to be up before connecting ")
				sleep 180
				uri = URI("http://#{ip}:9080/price/heartbeat/heartbeat.jsp")
				res = nil
				begin
					res = Net::HTTP.get_response(uri)
				rescue SystemCallError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, SocketError,
					   Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, Net::HTTPBroken => e
					Depac::Log.write("INFO", "Exception occurred while trying to connect to appserver with ip - #{ip}")
					Depac::Log.write("INFO", "#{e.message}")
					
						retry_count -= 1
      					Depac::Log.warn("Timeout Error: Trying #{retry_count} more times ")
	    				if retry_count > 0
	        				sleep 180
	      					retry
	    				else
	      					Depac::Log.fatal_exit("Timeout Error: reached max retry count for trying to connect to appserver with ip - #{ip}, exiting!")	      
	      					return false
	    				end		
	    				
				end
				if(res == nil)
					return false
				end	
				if(res.is_a?(Net::HTTPSuccess))
					Depac::Log.write("INFO", "Connection to Appserver url #{uri} successful ")					
          			restAutomationResult=true
					if(config['ifRunRestAutomation'] == true || config['ifRunRestAutomation'] == "true")
			            Depac::Log.write("INFO", "start to execute rest automation against app node with ip: #{ip} ")
			            restAutomationConfig="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestconfig_postfix']}"
			            restAutomationScript="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestscirpts_postfix']}"
			            restAutomationDirectory="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestdirectory_postfix']}"
			            restAutomationResult="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestresult_postfix']}"
			            Depac::Log.write("INFO", "rest automation configuration location: #{restAutomationConfig},script location: #{restAutomationScript},result location: #{restAutomationResult}") 
			                                
			            extraInfo={
			              "restAutomationConfig"=>restAutomationConfig,
			              "restAutomationScript"=>restAutomationScript,
			              "restAutomationDirectory"=>restAutomationDirectory,
			              "restAutomationResult"=>restAutomationResult,
			              "autotestcommand"=>config['autotestcommand'],
			              "autotestsever"=>config['autotestsever']
			            }
			            restAutomationResult= Depac::Utils.launchRestAutomation(buildLabel,ip,extraInfo)
			            Depac::Log.write("INFO", "end to execute rest automation against app node with ip: #{ip}, result: #{restAutomationResult}")
					end
					return restAutomationResult
				else
					Depac::Log.write("INFO", "Connection to Appserver url #{uri} failed with #{res.code} response code and message - #{res.message}")
					Depac::Log.write("INFO", "Response body - #{res.body}")
					return false
				end
			elsif(role == Depac::CloudDeploymentConstants::ROLE_AGENT)
				private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
				cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -o StrictHostKeyChecking=no 'service agentservice status|grep -c STOPPED'"
	            Depac::Log.write("INFO", "Executing command: " + cmdstr)
	            output =  `#{cmdstr}`
	            stoppedCount = output.to_i
	            if(stoppedCount>0)
	            	Depac::Log.write("ERROR", "#{stoppedCount} number of agent server process are down. Please investigate, agent server IP - #{ip} ")
	            	return false
	            else
	            	Depac::Log.write("INFO", "All agent server process appear to be running ")
	            	return true
	            end
	            
	        elsif(role == Depac::CloudDeploymentConstants::ROLE_INTG)
				private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
				cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -o StrictHostKeyChecking=no 'service intgservice status|grep -c STOPPED'"
	            Depac::Log.write("INFO", "Executing command: " + cmdstr)
	            output =  `#{cmdstr}`
	            stoppedCount = output.to_i
	            if(stoppedCount>0)
	            	Depac::Log.write("ERROR", "#{stoppedCount} number of integration server process are down. Please investigate, integration server IP - #{ip} ")
	            	return false
	            else
	            	Depac::Log.write("INFO", "All integration server process appear to be running ")
	            	return true
	            end	        
			end
			
		end
	end
end
def updateEnvConfigObject(newnodes,role,existingEnvConfigObject,buildLabel)
	config = existingEnvConfigObject.getNodeConfigurationByRoleAndType(role,Depac::CloudDeploymentConstants::RUNTIME_NODES)
	nodeInfo = config[Depac::CloudDeploymentConstants::NODE_INFO]
	snapshotname = buildFlexImageNameByRoleBuildLabelAndType(role, buildLabel, Depac::CloudDeploymentConstants::RUNTIME_NODES, false)
	count = 0
	servers = []
	newnodes.each do |nodeconfig|
		nodeconfig[Depac::CloudDeploymentConstants::RUNTIME_NODES][role].each do |newInfo|
			nodeInfo.push(newInfo)
			if(newInfo["info"]!=nil)
				servers.push({"server_name"=>newInfo["info"]})
			end
			count += 1
		end
	end
	if(role == Depac::CloudDeploymentConstants::ROLE_APPSERVER)
		config[Depac::CloudDeploymentConstants::NO_OF_NODES] += count
	elsif(role == Depac::CloudDeploymentConstants::ROLE_AGENT)
		config[Depac::CloudDeploymentConstants::AGENT_NODES]=servers		
	elsif(role == Depac::CloudDeploymentConstants::ROLE_INTG)
		config[Depac::CloudDeploymentConstants::INTG_NODES]=servers
	end
	config["snapshot"]=snapshotname
end
def updateBuildLable(existingEnvConfigObject,buildLabel)
	envconfig = existingEnvConfigObject.getEnvironmentConfiguration()
	envconfig["build_label"]=buildLabel
end
#docker poc
def updateInternalForDocker(existingEnvConfigObject,buildLabel,delay,role)

  if existingEnvConfigObject.getNodeConfigurationByRoleAndType(role,Depac::CloudDeploymentConstants::RUNTIME_NODES) !=nil

	startTime=Time.now
	Depac::Log.write("INFO", "#{role} update started at #{startTime}")
	oldBuildLabel = existingEnvConfigObject.getBuildLabel()
	#read the details of existing app nodes	
	config = existingEnvConfigObject.getNodeConfigurationByRoleAndType(role,Depac::CloudDeploymentConstants::RUNTIME_NODES)
	count = config[Depac::CloudDeploymentConstants::NO_OF_NODES]
	nodeInfo = config[Depac::CloudDeploymentConstants::NODE_INFO]
       Depac::Log.write("INFO", "nodeInfo is: #{nodeInfo}")
	if(count == nil)
		count = nodeInfo.length
	end
	Depac::Log.write("INFO", "#{role} has #{count} nodes in total")

	for i in 1..count
        	
		addConfigObject=nil
		if(role == Depac::CloudDeploymentConstants::ROLE_APPSERVER)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
	   		 	"no_of_nodes"=> 1
	   		 	}]
	   		}	
		elsif(role == Depac::CloudDeploymentConstants::ROLE_AGENT)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
	   		 	Depac::CloudDeploymentConstants::AGENT_NODES=> [{"server_name"=>nodeInfo[i-1]["info"]}]
	   		 	}]
	   		}
	   	elsif(role == Depac::CloudDeploymentConstants::ROLE_INTG)
			addConfigObject = {
			Depac::CloudDeploymentConstants::RUNTIME_NODES=>
				[{
				"role"       => role,
	   		 	Depac::CloudDeploymentConstants::INTG_NODES=> [{"server_name"=>nodeInfo[i-1]["info"]}]
	   		 	}]
	   		}
		end
   		
   	    temp = existingEnvConfigObject.clone
		temp.setEnvironmentConfiguration(addConfigObject)
		Depac::Log.write("INFO", "temp is : #{temp}")

		nodeInfoMap = buildNodeInfoMapWithCount(existingEnvConfigObject,role,i)
		Depac::Log.write("INFO", "nodeInfoMap is : #{nodeInfoMap}")

		nodeInfoParamMap = buildNodeInfoParamMap(existingEnvConfigObject)	
        Depac::Log.write("INFO", "nodeInfoParamMap is : #{nodeInfoParamMap }")

		# we need firstly remove appserver from IHS, then startup appserver container, and add the same appserver back to IHS
		if role == Depac::CloudDeploymentConstants::ROLE_APPSERVER
		    # update IHS plugin configure
			Depac::Log.write("INFO", "remove appserver from IHS: #{nodeInfoMap}")
	        updateIHSPlugin_internal(nodeInfoMap, Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH, existingEnvConfigObject.getEnvironmentConfiguration(), "remove")
		end

		provisionInstanceForDocker(temp, buildLabel, existingEnvConfigObject.getEnvironmentName(), 1, existingEnvConfigObject, true)
        	
		# configure instance
		configureInstanceForDocker(nodeInfoMap, nodeInfoParamMap, existingEnvConfigObject.getEnvironmentConfiguration())
		
		if (validateNodeForDocker(nodeInfoMap,buildLabel,existingEnvConfigObject.getEnvironmentConfiguration()))		    
           #add back appserver after validation.
		   if role == Depac::CloudDeploymentConstants::ROLE_APPSERVER
            # update IHS plugin configure
            Depac::Log.write("INFO", "add back appserver from IHS: #{nodeInfoMap}")
            updateIHSPlugin_internal(nodeInfoMap, Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH, existingEnvConfigObject.getEnvironmentConfiguration(), "add")
           end
		   #docker poc TODO: remove old docker container
		   Depac::Utils.deleteEnvironmentForDocker(nodeInfoMap)
		   Depac::Log.write("INFO", "removing old #{role} instance:#{nodeInfoMap}")
		else
      #docker poc TODO: roll back to previous docker container old instance
		  Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)
		  Depac::Log.write("INFO", "validate process detected error, roll back to previous environment")
      Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)
			
			exit 3
		end 		
	end
	return existingEnvConfigObject
  end	
end
#docker poc
def validateNodeForDocker(nodeInfoMap,buildLabel,config)
	
	nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES].each do |role, nodeInfoArr|
		nodeInfoArr.each do |hostnameIPMap|
			hostname = hostnameIPMap['hostname']
			ip = hostnameIPMap['IP']
			Depac::Log.write("INFO", "Validating Instance with ip #{ip} for role #{role} ")
			retry_count = 1
			
			if(role==Depac::CloudDeploymentConstants::ROLE_APPSERVER)
				Depac::Log.write("INFO", "Waiting for appserver to be up before connecting ")
				sleep 10
				uri = URI("http://#{ip}:9080/price/heartbeat/heartbeat.jsp")
				Depac::Log.write("INFO", "try heartbeat...")

				res = nil
				begin
					res = Net::HTTP.get_response(uri)
				rescue SystemCallError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, SocketError,
					   Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, Net::HTTPBroken => e
					Depac::Log.write("INFO", "Exception occurred while trying to connect to appserver with ip - #{ip}")
					Depac::Log.write("INFO", "#{e.message}")
					
						retry_count -= 1
      					Depac::Log.warn("Timeout Error: Trying #{retry_count} more times ")
	    				if retry_count > 0
	        				sleep 10
	      					retry
	    				else
	      					Depac::Log.fatal_exit("Timeout Error: reached max retry count for trying to connect to appserver with ip - #{ip}, exiting!")	      
	      					return false
	    				end		
	    				
				end
				if(res == nil)
					return false
				end	
				if(res.is_a?(Net::HTTPSuccess))
					Depac::Log.write("INFO", "Connection to Appserver url #{uri} successful ")					
          			restAutomationResult=true
					if(config['ifRunRestAutomation'] == true || config['ifRunRestAutomation'] == "true")
			            Depac::Log.write("INFO", "start to execute rest automation against app node with ip: #{ip} ")
			            restAutomationConfig="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestconfig_postfix']}"
			            restAutomationScript="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestscirpts_postfix']}"
			            restAutomationDirectory="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestdirectory_postfix']}"
			            restAutomationResult="#{config['autotest_prefix']}/#{buildLabel}/#{config['autotestresult_postfix']}"
			            Depac::Log.write("INFO", "rest automation configuration location: #{restAutomationConfig},script location: #{restAutomationScript},result location: #{restAutomationResult}") 
			                                
			            extraInfo={
			              "restAutomationConfig"=>restAutomationConfig,
			              "restAutomationScript"=>restAutomationScript,
			              "restAutomationDirectory"=>restAutomationDirectory,
			              "restAutomationResult"=>restAutomationResult,
			              "autotestcommand"=>config['autotestcommand'],
			              "autotestsever"=>config['autotestsever']
			            }
				     #docker poc TODO: add rest automation to validate app server.
			            #restAutomationResult= Depac::Utils.launchRestAutomation(buildLabel,ip,extraInfo)
			            Depac::Log.write("INFO", "end to execute rest automation against app node with ip: #{ip}, result: #{restAutomationResult}")
					end
					return restAutomationResult
				else
					Depac::Log.write("INFO", "Connection to Appserver url #{uri} failed with #{res.code} response code and message - #{res.message}")
					Depac::Log.write("INFO", "Response body - #{res.body}")
					return false
				end
			elsif(role == Depac::CloudDeploymentConstants::ROLE_AGENT)
				private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
				cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -p #{hostnameIPMap['sshPort']} -o StrictHostKeyChecking=no 'service agentservice status|grep -c STOPPED'"
	            Depac::Log.write("INFO", "Executing command: " + cmdstr)
	            output =  `#{cmdstr}`
	            stoppedCount = output.to_i
	            if(stoppedCount>0)
	            	Depac::Log.write("ERROR", "#{stoppedCount} number of agent server process are down. Please investigate, agent server IP - #{ip} ")
	            	return false
	            else
	            	Depac::Log.write("INFO", "All agent server process appear to be running ")
	            	return true
	            end
	            
	        elsif(role == Depac::CloudDeploymentConstants::ROLE_INTG)
				private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
				cmdstr = "ssh -t -t -i #{private_key_path} root@#{ip} -p #{hostnameIPMap['sshPort']} -o StrictHostKeyChecking=no 'service intgservice status|grep -c STOPPED'"
	            Depac::Log.write("INFO", "Executing command: " + cmdstr)
	            output =  `#{cmdstr}`
	            stoppedCount = output.to_i
	            if(stoppedCount>0)
	            	Depac::Log.write("ERROR", "#{stoppedCount} number of integration server process are down. Please investigate, integration server IP - #{ip} ")
	            	return false
	            else
	            	Depac::Log.write("INFO", "All integration server process appear to be running ")
	            	return true
	            end	        
			end
			
		end
	end
end
